#include <qgl.h>
#include "surfacemesh_render_transparent.h"
#include "surface_mesh/gl_wrappers.h"

typedef Surface_mesh::Face_iterator FaceItr;
typedef std::pair<double, FaceItr> DepthFace;
bool depthSorter(DepthFace i, DepthFace j){ return (i.first < j.first); }

void surfacemesh_render_transparent::render(){
    Surface_mesh::Vertex_property<Point>  points = mesh()->vertex_property<Point>("v:point");    
	Surface_mesh::Vertex_property<Point>  vnormals = mesh()->vertex_property<Point>("v:normal");

	// Deal with color
	bool has_vertex_color = mesh()->has_vertex_property<Color>("v:color");
	Surface_mesh::Vertex_property<Color>  vcolor;
	if (has_vertex_color) vcolor = mesh()->get_vertex_property<Color>("v:color");

	Surface_mesh::Vertex_around_face_circulator fvit, fvend;

	/// Sort faces
	std::vector< DepthFace > depthvec;
	{
		triangles.clear();
		triangles.resize(mesh()->n_faces());

		// Get current view transforms
		GLdouble projMatrix[16], modelMatrix[16];
		glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
		glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);

		// Temporary variables for projection
		double depth,x,y;
		GLint viewport[4] = {0, 100, 100, -100};

		/// Apply model transform and fill in depth & indexes
		Surface_mesh::Face_iterator fit, fend = mesh()->faces_end();
		for (fit = mesh()->faces_begin(); fit != fend; ++fit){

			// Compute face center
			Vector3 faceCenter(0,0,0);
			fvit = fvend = mesh()->vertices(fit); int c = 0;
			do{ faceCenter += points[fvit]; c++; } while (++fvit != fvend);
			faceCenter /= c;

			// Project to get range 0 - 1.0
			gluProject(faceCenter.x(),faceCenter.y(),faceCenter.z(), modelMatrix, projMatrix, viewport,&x,&y,&depth);

			depthvec.push_back(DepthFace(depth, fit));
		}

		/// Sort depth 
		std::sort(depthvec.begin(), depthvec.end(), depthSorter);
	}

	/// Render
	{
		glShadeModel(GL_SMOOTH);
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		glEnable(GL_LIGHTING);
		glEnable(GL_NORMALIZE);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glDisable(GL_DEPTH_TEST);
		glDisable(GL_CULL_FACE);
		{
            if(!has_vertex_color){
                Vec4d colorv(mesh()->color);
                /// @todo minimum 10% transparency
                colorv[3] = qMin(.1,colorv[3]);
                glColor4dv(colorv);
            }
			glBegin(GL_TRIANGLES); 
			foreach(DepthFace f, depthvec)
			{
				FaceItr fit = f.second;
				fvit = fvend = mesh()->vertices(fit);

				do{	
					if(has_vertex_color){
						// Fog like effect
						glColor4dv(Vec4d(vcolor[fvit][0],vcolor[fvit][1],vcolor[fvit][2], 1 - f.first));
					}

					gl::glNormal(vnormals[fvit]);
					gl::glVertex(points[fvit]); 
				} while (++fvit != fvend);
			}
			glEnd();
		}
		glEnable(GL_DEPTH_TEST);
		glEnable(GL_CULL_FACE);
	}
}

Q_EXPORT_PLUGIN(surfacemesh_render_transparent)
